#include "stdlib.hpp"
#include <purewell/condition.hpp>
#include <purewell/mutex.hpp>

namespace purewell
{

PWConditionAttribute::PWConditionAttribute()
{
	pthread_condattr_t* pthis(new pthread_condattr_t);
	if ( !pthis ) return;

	if ( 0 != pthread_condattr_init(pthis) )
	{
		delete pthis;
		return;
	}

	m_pData = pthis;
	return;
}

PWConditionAttribute::~PWConditionAttribute()
{
	if ( m_pData )
	{
		pthread_condattr_t* pthis((pthread_condattr_t*)m_pData);
		delete pthis;
		m_pData = NULL;
	}
}

void
PWConditionAttribute::release(PWConditionAttribute* obj)
{
	delete obj;
}

PWConditionAttribute*
PWConditionAttribute::create(void)
{
	PWConditionAttribute* ret(new PWConditionAttribute);
	if ( !ret ) return NULL;
	if ( !ret->m_pData )
	{
		delete ret;
		return NULL;
	}

	return ret;
}

bool
PWConditionAttribute::setProcessShared(bool value)
{
	pthread_condattr_t* pthis((pthread_condattr_t*)m_pData);
	const int type(value?PTHREAD_PROCESS_SHARED:PTHREAD_PROCESS_PRIVATE);
	return 0 == pthread_condattr_setpshared(pthis, type);
}

bool
PWConditionAttribute::getProcessShared(void) const
{
	int ret;
	pthread_condattr_t* pthis((pthread_condattr_t*)m_pData);
	if ( 0 != pthread_condattr_getpshared(pthis, &ret) )
	{
		return false;
	}

	return (PTHREAD_PROCESS_SHARED == ret);
}

PWCondition*
PWCondition::create(const PWConditionAttribute* pattr)
{
	pthread_cond_t* pcond(new pthread_cond_t);
	if ( !pcond )
	{
		_PWTRACE("%s", "not enough memory");
		return NULL;
	}

	pthread_condattr_t* pcondattr(NULL);
	if ( pattr )
	{
		pcondattr = (pthread_condattr_t*)(pattr->getData());
	}

	do
	{
		int res( pthread_cond_init(pcond, pcondattr) );
		if ( 0 != res )
		{
			_PWTRACE("%s", strerror(res));
			break;
		}

		PWCondition* ret(new PWCondition);
		if ( NULL == ret )
		{
			_PWTRACE("%s", "not enough memory");
			break;
		}

		ret->m_pData = pcond;
		return ret;
	} while (false);

	if ( pcond )
	{
		delete pcond;
		pcond = NULL;
	}

	return NULL;
}

void
PWCondition::release(PWCondition* obj)
{
	delete obj;
}

PWCondition::PWCondition()
{
}

PWCondition::~PWCondition()
{
	if ( m_pData )
	{
		pthread_cond_t* pthis((pthread_cond_t*)m_pData);
		delete pthis;
		m_pData = NULL;
	}
}

void
PWCondition::signal(void)
{
	pthread_cond_signal((pthread_cond_t*)m_pData);
}

void
PWCondition::broadcast(void)
{
	pthread_cond_broadcast((pthread_cond_t*)m_pData);
}

void
PWCondition::wait(PWMutex& mutex)
{
	pthread_cond_wait((pthread_cond_t*)m_pData,
		(pthread_mutex_t*)mutex.getData());
}

bool
PWCondition::wait(PWMutex& mutex, struct timespec& ts)
{
	return 0 != pthread_cond_timedwait(
		(pthread_cond_t*)m_pData,
		(pthread_mutex_t*)mutex.getData(),
		&ts);
}

bool
PWCondition::wait(PWMutex& mutex, size_t msec)
{
	struct timespec ts;
	ts.tv_sec = msec / 1000;
	ts.tv_nsec = (msec % 1000) * 1000000L;
	return 0 != pthread_cond_timedwait(
		(pthread_cond_t*)m_pData,
		(pthread_mutex_t*)mutex.getData(),
		&ts);
}

};//namespace purewell

